package defectsim;
// i�te bu kadar
import java.text.SimpleDateFormat;
import java.util.Calendar;

import repast.simphony.space.continuous.NdPoint;

public class Util {

	private static final String DATE_FORMAT_NOW = "dd_MM_yyyy_HH_mm_ss";

	public static double calculateDistance(NdPoint p1, NdPoint p2){

		double distance = Math.sqrt((Math.pow(p1.getY() - p2.getY(), 2) + 
				Math.pow(p1.getX() - p2.getX(), 2)));

		return distance;
	}
	// Minimum image convention
	public static double calculateMICDistance(NdPoint p1, NdPoint p2, double length){

		double xx = p2.getX() - p1.getX();
		double yy = p2.getY() - p1.getY();
		double dx = xx - length * Math.round(xx / length);
		double dy = yy - length * Math.round(yy / length);
		
		return Math.sqrt(dx * dx + dy * dy);
	}
	
	public static double calculateMICDistance(double p1, double p2, double length){

		double dd = p2 - p1;
		double distance = dd - length * Math.round(dd / length);
		
		return distance;
	}
	
	public static double calculateAngle(NdPoint p1, NdPoint p2){
//		If you want the angle bewteen the vectors OP1 and OP2 (O being the origin), you should know that the dot product between two vectors u and v is:
//			u . v = u.x * v.x + u.y * v.y = |u|*|v|*cos(a)
//			a being the angle between the vectors.
//			So the angle is given by:
//			double n1 = sqrt(x1*x1+y1*y1), n2 = sqrt(x2*x2+y2*y2);
//			double angle = acos((x1*x2+y1*y2)/(n1*n2)) * 180 / PI;
//

		double dx;
		double dy;

		dx = p2.getX() - p1.getX();
		dy = p2.getY() - p1.getY();
		double angle = StrictMath.atan2(dy, dx);
		while(0 > angle) {
			angle += 2.0 * Math.PI;
		}

		return angle;
	}
	
	public static double calculateMICAngle(NdPoint p1, NdPoint p2, double length){
		double xx = p2.getX() - p1.getX();
		double yy = p2.getY() - p1.getY();
		double dx = xx - length * Math.round(xx / length);
		double dy = yy - length * Math.round(yy / length);
//		dx = p1.getX() + dx;
//		dy = p1.getY() + dy;
		double angle = StrictMath.atan2(dy, dx);
		while(0 > angle) {
			angle += 2.0 * Math.PI;
		}

		return angle;
	}

	public static String now() {
		Calendar cal = Calendar.getInstance();
		SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_NOW);
		return sdf.format(cal.getTime());

	}

	public static double calculateTotalLongRangeStress(Dislocation di, Iterable<Dislocation> longRangeNeighbours, 
			SimEnvironment env, double pRadius){
		double stress = 0.0;
		NdPoint p1 = env.getLocation(di);
		for (Dislocation dj : longRangeNeighbours) {
			NdPoint p2 = env.getLocation(dj);
			double dist = Util.calculateMICDistance(p1, p2, env.getSpaceLength());
			double delta = Util.calculateMICAngle(p1, p2, env.getSpaceLength());
			if (dist > 0 && dist <= pRadius)
				stress = stress + calculateGlideStressInCylindiricalCoordinates(dist, delta, di, dj, 
						env.getCurrentMaterial(), env.getSpaceLength());
//				stress = stress + calculateGlideStressInCartesianCoordinates(p1, p2, dis.getUnitBurgersVector(), 
//						env.getCurrentMaterial(), env.getSpaceLength());
		}

		return stress;
	}
	
	public static double[] calculateTotalLongRangeStressForRK4(Dislocation di, Iterable<Dislocation> longRangeNeighbours, 
			SimEnvironment env, double pRadius){
		double[] stress = new double[4];
		// Coefficients for RK4
		double k1 = 0;
		double k2 = 0;
		double k3 = 0;
		double k4 = 0;
		double k = 0;
		double dt = env.getTimeStep();
		NdPoint p1 = env.getLocation(di);
		for (Dislocation dj : longRangeNeighbours) {
			NdPoint p2 = env.getLocation(dj);
			double dist = Util.calculateMICDistance(p1, p2, env.getSpaceLength());
			double delta = Util.calculateMICAngle(p1, p2, env.getSpaceLength());
			if (dist > 0 && dist <= pRadius){
				k1 = k1 + calculateGlideStressInCylindiricalCoordinates(dist, delta, di, dj, 
						env.getCurrentMaterial(), env.getSpaceLength());
				k = k1 * dt / 2;
				k2 = k2 + calculateGlideStressInCylindiricalCoordinates(dist + k, delta, di, dj, 
					env.getCurrentMaterial(), env.getSpaceLength());
				k = k2 * dt / 2;
				k3 = k3 + calculateGlideStressInCylindiricalCoordinates(dist + k, delta, di, dj, 
					env.getCurrentMaterial(), env.getSpaceLength());
				k = k3 * dt;
				k4 = k4 + calculateGlideStressInCylindiricalCoordinates(dist + k, delta, di, dj, 
					env.getCurrentMaterial(), env.getSpaceLength());
			}
//				stress = stress + calculateGlideStressInCartesianCoordinates(p1, p2, dis.getUnitBurgersVector(), 
//						env.getCurrentMaterial(), env.getSpaceLength());
		}
		double c = 10;
		stress[0] = k1/c + env.getCurrentExternalStress() - env.getCurrentFrictionStress();
		stress[1] = k2/c + env.getCurrentExternalStress() - env.getCurrentFrictionStress();
		stress[2] = k3/c + env.getCurrentExternalStress() - env.getCurrentFrictionStress();
		stress[3] = k4/c + env.getCurrentExternalStress() - env.getCurrentFrictionStress();
		
		return stress;
	}
	
	public static double calculateGlideStressInCylindiricalCoordinates(double r, double delta, Dislocation di, Dislocation dj, Material mat, double length){
//		double r = Util.calculateMICDistance(p1, p2, length);
//		double delta = Util.calculateMICAngle(p1, p2, length);
//		double r = Util.calculateDistance(p1, p2);
//		double delta = Util.calculateAngle(p1, p2);

		double teta = delta - Math.toRadians(di.getDirection());
		double gamma = delta - Math.toRadians(dj.getDirection());
		
		r *= 1000;

		double A = (mat.getShearModulus() * dj.getUnitBurgersVector() * mat.getBurgersVector()) / 
		(2 * Math.PI * (1 - mat.getPoissonRatio()));

		double sGlide = A * Math.cos(teta) * Math.cos(2 * gamma)/ r;

		return sGlide;
	}
	
	public static double calculateGlideStressInCartesianCoordinates(NdPoint p1, NdPoint p2, double unitBurgersVector, Material mat, double length){
		double x1 = p1.getX();
		double y1 = p1.getY();
		double x2 = p2.getX();
		double y2 = p2.getY();
		
		double dx = calculateMICDistance(x1, x2, length) * 1000;
		double dy = calculateMICDistance(y1, y2, length) * 1000;
		double dx2 = dx * dx;
		double dy2 = dy * dy;
		double dx2dy2 = dx2 + dy2;

		double A = (mat.getShearModulus() * unitBurgersVector * mat.getBurgersVector()) / 
		(2 * Math.PI * (1 - mat.getPoissonRatio()));

		double sGlide = A * (dx * (dx2 - dy2)) / (dx2dy2 * dx2dy2);

		return sGlide;
	}

}
